package com.radar.visualize;

import cn.hutool.core.date.DateUtil;
import com.radar.algorithm.MathCommon;
import com.radar.common.DateConstants;
import com.radar.common.ProductType;
import com.radar.exception.RadarCaclError;
import com.radar.exception.RadarDecodeError;
import com.radar.exception.RadarVisualizeError;
import com.radar.io.VCSData;
import com.radar.io.cinrad.BaseCinrad;
import org.meteoinfo.global.PointD;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.List;

public class VCSMap extends ThematicMap {

    public VCSMap(BaseCinrad radar) {
        super(radar);
    }

    private VCSData vcsData;

    public VCSData getVcsData(){
        return this.vcsData;
    }

    //region vcs info

    public static class VCSInfo {

        /**
         * radar element
         */
        private ProductType type;

        /**
         * Whether to display the scale axis
         */
        private boolean axis = true;

        /**
         * if null ? Default background color blacs
         */
        private Color backColor = Color.black;

        /**
         * draw radar site detail on right
         */
        private boolean simpleDetail = true;

        /**
         * Number of height interpolation
         */
        private int altNum = 500;

        /**
         * Number of latitude and longitude interpolation
         */
        private int pointNum = 100;

        /**
         * Maximum height (km)
         */
        private double maxAlt = 22;

        public VCSMap.VCSInfo maxAlt(int maxAlt) {
            this.maxAlt = maxAlt;
            return this;
        }

        public VCSMap.VCSInfo altNum(int altNum) {
            this.altNum = altNum;
            return this;
        }

        public VCSMap.VCSInfo pointNum(int pointNum) {
            this.pointNum = pointNum;
            return this;
        }

        public VCSMap.VCSInfo type(ProductType type) {
            this.type = type;
            return this;
        }

        public VCSMap.VCSInfo backColor(Color backColor) {
            this.backColor = backColor;
            return this;
        }

        public VCSMap.VCSInfo axis(boolean axis) {
            this.axis = axis;
            return this;
        }

        public VCSMap.VCSInfo simpleDetail(boolean simpleDetail) {
            this.simpleDetail = simpleDetail;
            return this;
        }

    }

    public static VCSMap.VCSInfo buildRasterInfo(ProductType type) {
        VCSMap.VCSInfo vcsInfo = new VCSMap.VCSInfo();
        return vcsInfo.type(type);
    }

    public BufferedImage simpleVCS(VCSMap.VCSInfo vcsInfo, List<PointD> pointDList) throws RadarDecodeError, RadarCaclError, RadarVisualizeError {
        VCSData vcs = this.radar.vcs(pointDList, vcsInfo.pointNum, vcsInfo.altNum, vcsInfo.type, vcsInfo.maxAlt);
        this.vcsData = vcs;
        RasterMap rasterMap = new RasterMap(this.radar);
        BufferedImage bufferedImage = rasterMap.drawSingleRaster(vcs.data,ProductType.REF);
        int vcsWidth = bufferedImage.getWidth();
        int vcsHeight = bufferedImage.getHeight();

        int xOffset = 0;
        int yOffset = 0;

        int width = 1000;
        int height = (int) (vcsHeight / (vcsWidth + 0.0) * 1000);
        if (vcsInfo.axis) {
            // 左坐标轴
            width += 50;
            xOffset += 50;
            // 左右空白
            width += 40;
            xOffset += 20;
            // 下坐标轴
            height += 50;
            // 上下空白
            height += 40;
            yOffset += 20;
        }
        if (vcsInfo.simpleDetail) {
            // title
            height += 50;
            yOffset += 50;
            // legend
            width += 80;
        }
        BufferedImage br = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = br.createGraphics();
        try {
            g.setBackground(vcsInfo.backColor);
            g.clearRect(0, 0, width, height);
            g.setPaint(vcsInfo.backColor);
            g.drawOval(0, 0, width, height);
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);

            Image scaledInstance = bufferedImage.getScaledInstance(1000, (int) (vcsHeight / (vcsWidth + 0.0) * 1000), Image.SCALE_SMOOTH);
            g.drawImage(scaledInstance, xOffset, yOffset, null);

            if (vcsInfo.simpleDetail) {
                Font font = new Font("Arial", Font.PLAIN, 20);
                g.setFont(font);
                g.setColor(new Color(255 - vcsInfo.backColor.getRed(), 255 - vcsInfo.backColor.getGreen(), 255 - vcsInfo.backColor.getBlue(), 240));
                FontMetrics fm = g.getFontMetrics(font);
                String title = "Vertical cross-section " + vcsInfo.type.getFullName() + " (" + vcsInfo.type.getUnit() + ")";
                g.drawString(title, width / 2 - fm.stringWidth(title) / 2, 20);
                // detail
                font = new Font("Arial", Font.BOLD, 12);
                g.setFont(font);
                g.setColor(new Color(255 - vcsInfo.backColor.getRed(), 255 - vcsInfo.backColor.getGreen(), 255 - vcsInfo.backColor.getBlue(), 230));
                fm = g.getFontMetrics(font);
                title = String.format("Station: %s Start: %s %s End: %s %s Time: %s Max: %s", this.radar.getRadarSite().getStationName(),
                        simpleDoubleText(pointDList.get(0).X) + "", simpleDoubleText(pointDList.get(0).Y) + "",
                        simpleDoubleText(pointDList.get(pointDList.size() - 1).X) + "", simpleDoubleText(pointDList.get(pointDList.size() - 1).Y) + "",
                        DateUtil.format(radar.dateTime, DateConstants.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI),
                        simpleDoubleText(MathCommon.getMaxMinValue(this.vcsData.data)[0]) + "");
                g.drawString(title, width / 2 - fm.stringWidth(title) / 2, 40);
            }
            if (vcsInfo.axis) {
                int rh = scaledInstance.getHeight(null);
                int wh = scaledInstance.getWidth(null);
                g.drawRect(xOffset - 1,yOffset - 1,wh + 2,rh + 2);
                int index = vcsInfo.maxAlt > 10 ? 2 : 1;
                Stroke dash = new BasicStroke(1.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1.5f, new float[]{5, 3.5F,}, 0f);
                g.setStroke(dash);
                for(double i = 0 ; i <= vcsInfo.maxAlt ; i += index){
                    g.setColor(new Color(255 - vcsInfo.backColor.getRed(), 255 - vcsInfo.backColor.getGreen(), 255 - vcsInfo.backColor.getBlue(), 200));
                    g.drawString(simpleDoubleText(i),xOffset - 20,(int)(yOffset + rh - i / vcsInfo.maxAlt * rh));
                    if(i == 0){
                        continue;
                    }
                    g.setColor(new Color(255 - vcsInfo.backColor.getRed(), 255 - vcsInfo.backColor.getGreen(), 255 - vcsInfo.backColor.getBlue(), 128));
                    g.drawLine(xOffset - 5,(int)(yOffset + rh - i / vcsInfo.maxAlt * rh), xOffset + wh,(int)(yOffset + rh - i / vcsInfo.maxAlt * rh));
                }
                g.setStroke(new BasicStroke());
                Font font = new Font(null, Font.PLAIN, 10);
                FontMetrics fm = g.getFontMetrics(font);
                int step = (int)(Math.floor(vcs.lon.length / 10.0));
                g.setFont(font);
                g.setColor(new Color(255 - vcsInfo.backColor.getRed(), 255 - vcsInfo.backColor.getGreen(), 255 - vcsInfo.backColor.getBlue(), 255));
                for(double i = 0 ; i < vcs.lon.length ; i += step){
                    g.drawLine((int)(xOffset + wh - i / vcs.lon.length * wh),(yOffset + rh - 2),(int)(xOffset + wh - i / vcs.lon.length * wh),(yOffset + rh + 3));
                    String text = "(" + simpleDoubleText(vcs.lon[(int) i]) + ",";
                    String text1 = simpleDoubleText(vcs.lat[(int) i]) + ")";
                    g.drawString(text,(int)(xOffset + wh - i / vcs.lon.length * wh) - fm.stringWidth(text) / 2,(yOffset + rh + 20));
                    g.drawString(text1,(int)(xOffset + wh - i / vcs.lon.length * wh) - fm.stringWidth(text1) / 2,(yOffset + rh + 30));
                }
                font = new Font(null, Font.PLAIN, 18);
                AffineTransform affineTransform = new AffineTransform();
                affineTransform.rotate(Math.toRadians(270), 0, 0);
                g.setColor(new Color(255 - vcsInfo.backColor.getRed(), 255 - vcsInfo.backColor.getGreen(), 255 - vcsInfo.backColor.getBlue(), 230));
                Font rotatedFont = font.deriveFont(affineTransform);
                g.setFont(rotatedFont);
                g.drawString("Height(KM)",30,height / 2 + 40);
                g.setFont(new Font(null, Font.PLAIN, 12));
                drawLegend(g, vcsInfo.type, (xOffset + wh + 30), (int) (height * 0.75), 20, br, new Color(255 - vcsInfo.backColor.getRed(), 255 - vcsInfo.backColor.getGreen(), 255 - vcsInfo.backColor.getBlue(), 200));
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RadarVisualizeError(e.getMessage());
        } finally {
            if (g != null) {
                g.dispose();
            }
        }
        System.out.println();
        return br;
    }

    //endregion

}
